#include "NetPacketPool.h"
#include <string>
#include <cstring>
#include "NetConstants.h"
#include "NetPacket.h"

// 完成

namespace LiteNetLib
{
    NetPacketPool &NetPacketPool::GetInstance()
    {
        static NetPacketPool _NetPacketPool;
        return _NetPacketPool;
    }

    NetPacketPool::NetPacketPool()
    {
        uint32_t initPacketSize = NetConstants::PacketPoolSize / 4;
        for(uint32_t index = 0; index <  initPacketSize; index++)
        {
            NetPacket *netPacket = new NetPacket(NetConstants::MaxPacketSize);
            m_poolPacketQueue.push(netPacket);
        }
    }

    NetPacketPool::~NetPacketPool()
    {
        NetPacket *netPacket = nullptr;
        while(m_poolPacketQueue.try_pop(netPacket) == true)
        {
            delete netPacket;
        }
    }

    NetPacket *NetPacketPool::getWithData(PacketProperty property, const char* data, uint32_t length)
    {
        uint32_t headerSize = NetPacket::GetHeaderSize(property);
        auto netPacket = getPacket(length + headerSize);
        netPacket->getRawData()[0] = 0;
        netPacket->setProperty(property);
        memcpy((netPacket->getRawData() + headerSize), data, length);
        return netPacket;
    }

    NetPacket *NetPacketPool::getWithProperty(PacketProperty property, uint32_t size)
    {
        auto netPacket = getPacket(size + NetPacket::GetHeaderSize(property));
        netPacket->getRawData()[0] = 0;
        netPacket->setProperty(property);
        return netPacket;
    }

    NetPacket *NetPacketPool::getWithProperty(PacketProperty property)
    {
        auto netPacket = getPacket(NetPacket::GetHeaderSize(property));
        netPacket->getRawData()[0] = 0;
        netPacket->setProperty(property);
        return netPacket;
    }

    NetPacket *NetPacketPool::getPacket(uint32_t size)
    {
        if (size > NetConstants::MaxPacketSize)
        {
            return new NetPacket(size);
        }
        NetPacket *netPacket = nullptr;
        if(m_poolPacketQueue.try_pop(netPacket) == true)
        {
            netPacket->resetPacketSize(size);
            return netPacket;
        }
        return new NetPacket(size);
    }

    bool NetPacketPool::recycleOrDelete(NetPacket *netPacket)
    {
        // delete netPacket;
        // return false;

        if(netPacket == nullptr)
        {
            return false;
        }
        if (netPacket->getRawDataSize() > NetConstants::MaxPacketSize || m_poolPacketQueue.size() >= NetConstants::PacketPoolSize)
        {
            delete netPacket;
            return false;
        }
        netPacket->getRawData()[0] = 0;
        m_poolPacketQueue.push(netPacket);
        return true;
    }

}